package jmu.edu.yjc.server;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonFormat;
import jmu.edu.yjc.constants.SystemConstants;
import jmu.edu.yjc.domain.bo.MessageBo;
import jmu.edu.yjc.domain.entity.Message;
import jmu.edu.yjc.domain.entity.UnAnsweredQuestion;
import jmu.edu.yjc.domain.entity.User;
import jmu.edu.yjc.domain.vo.user.UserContactVo;
import jmu.edu.yjc.service.MessageService;
import jmu.edu.yjc.service.UnAnsweredQuestionService;
import jmu.edu.yjc.service.answer.AnswerService;
import jmu.edu.yjc.service.user.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

@ServerEndpoint(value = "/websocket/{id}")
@Component
public class WebSocketServer {
    Logger log = LoggerFactory.getLogger(this.getClass());
    private static ApplicationContext applicationContext;
    public static AnswerService answerService;
    public static void setAnswerService(AnswerService answerService) {
        WebSocketServer.answerService = answerService;
    }

    public static void setApplicationContext(ApplicationContext applicationContext) {
        WebSocketServer.applicationContext = applicationContext;
    }
    private static UnAnsweredQuestionService unAnsweredQuestionService;

    public static void setUnAnsweredQuestionService(UnAnsweredQuestionService unAnsweredQuestionService) {
        WebSocketServer.unAnsweredQuestionService = unAnsweredQuestionService;
    }

    private static StringRedisTemplate stringRedisTemplate;

    public static void setStringRedisTemplate(StringRedisTemplate stringRedisTemplate) {
        WebSocketServer.stringRedisTemplate = stringRedisTemplate;
    }
    public static UserService userService;

    public static void setUserService(UserService userService) {
        WebSocketServer.userService = userService;
    }

    public static MessageService messageService;

    public static void setMessageService(MessageService messageService) {
        WebSocketServer.messageService = messageService;
    }
    public static User robot;

    /**
     * 用来记录session_id与用户id之间的关系
     */
    public static Map<Long, Session> webSocketMap = new ConcurrentHashMap<>();
    //静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
   public static int onlineCount = 0;

    //concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
    public static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();

    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;
    @OnOpen
    public void open(@PathParam("id") Long id, Session session){
        webSocketMap.put(id,session);
        this.session = session;
        webSocketSet.add(this);     //加入set中
        addOnlineCount();           //在线数加1
        if(robot == null){
            robot = userService.getRobot();
        }
        log.info("用户"+id+"连接"+session.getAsyncRemote());
    }
    @OnMessage
    public void message(@PathParam("id")Long id ,Session session ,String message) throws IOException, InterruptedException {
        JSONObject object = JSONObject.parseObject(message);
        if("heartbeat".equals(object.getString("type"))){
            return;
        }
        String toUserId = object.getString("toContactId");
        if(SystemConstants.USER_ROBOT.equals(toUserId)){
            robotSend(object,id);
        }else {
            sendToUser(object,id,message);
        }
    }
    private void sendToUser(JSONObject object,Long userID, String message){
        Map<String, String> map = new HashMap<>();
        map.put("toUserId",object.getString("toContactId"));
        map.put("userId", userID.toString());
        map.put("message", message);
        map.put("flag", "send");
        stringRedisTemplate.convertAndSend(SystemConstants.REDIS_CHANNEL_SEND, JSONObject.toJSONString(map));
    }
    private void robotSend(JSONObject object,Long userID) throws IOException, InterruptedException {
        String question = object.getString("content");
        List<String> answer = answerService.getAnswer(question, userID);
        JSONObject answerMap = new JSONObject();
        answerMap.put("type","text");
        answerMap.put("messageStatus","success");
        answerMap.put("toContactId",userID);
        JSONObject fromUser = new JSONObject();
        fromUser.put("id",robot.getId());
        fromUser.put("displayName",robot.getNickName());
        fromUser.put("avatar",robot.getAvatar());
        answerMap.put("fromUser",fromUser);
        if(answer.size()>0){
            for (String s : answer) {
                Thread.sleep(1000);
                answerMap.put("id",UUID.randomUUID());
                answerMap.put("content",s+"。");
                answerMap.put("sentTime",new Date().getTime());
                Session session = webSocketMap.get(userID);
                session.getBasicRemote().sendText(answerMap.toJSONString());
            }
        }else {
            answerMap.put("id",UUID.randomUUID());
            answerMap.put("content","很抱歉您所问的问题小C暂时不能为您作答,但是您的问题已经被记录，\n" +
                    "感谢您的使用，请试试问问其他问题吧！QAQ");
            answerMap.put("sentTime",new Date().getTime());
            Session session = webSocketMap.get(userID);
            session.getBasicRemote().sendText(answerMap.toJSONString());
        }
    }
    //统一发送消息
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }
    @OnClose
    public void close(@PathParam("id")Long id ,Session session ){
        webSocketMap.remove(id);
        webSocketSet.remove(this);
        subOnlineCount();
        log.info("用户"+id+"断开连接");
    }

    /**
     * 群发自定义消息
     * */
    public static void sendInfo(String message) throws IOException {
        for (WebSocketServer item : webSocketSet) {
            try {
                item.sendMessage(message);
            } catch (IOException e) {
                continue;
            }
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }
}
